import asyncio
import websockets
import os
from pathlib import Path
from flask import Flask, request, jsonify
import threading
import subprocess
import logging
import uuid
import time
import platform
import signal
# 假设这些模块已经正确定义
from videofilesystem import build_video_queue, get_parent_dir, modify_queue_info, extract_videos_direct, mark_video_processed, read_video_queue_from_json, mount_usb
from videofilesystem import extract_parent_directory, get_latest_image
import json
from queue import Queue
from cpp_status import is_npu_idle
import getcamerainfo
import manager
import sendcameradealinfo
from sendfile import VideoAPIUploader
import videofilesystem
from gengif import EventUploader
from gen_config import create_video_config, gen_sdkconfig
import subprocess
from set_camera_status import change_video_state


class VideoProcessingApp:
    def __init__(self,
                 root_dir="/data/mn4",
                 output_dir="generated_images",
                 host='0.0.0.0',
                 port=5000,
                 lastest_img="test.jpg",
                 send_interval=1,
                 ws_port=8765):
        self.app = Flask(__name__)
        self.root_dir = root_dir
        self.output_dir = output_dir
        self.host = host
        self.port = port
        self.demonstrate = False
        self.cpp_pid = -1
        self.run_moive_task = ""
        self.is_paused = False
        self.video_queue = build_video_queue(self.root_dir)
        self.processing_thread = None
        os.makedirs(self.output_dir, exist_ok=True)
        self._register_routes()
        self.lastest_img = lastest_img
        self.SEND_INTERVAL = send_interval
        self.WS_PORT = ws_port

    def _register_routes(self):
        @self.app.route('/start', methods=['POST'])
        def _start():
            return self.run_program()

        @self.app.route('/demonstrate_start', methods=['POST'])
        def _demonstrate_start():
            action = request.json.get('action') if request.is_json else None
            return self.demonstrate_start(action=action)

        @self.app.route('/read', methods=['POST'])
        def _getdiskinfo():
            return self.self_mount_usb()

        @self.app.route('/pause', methods=['POST'])
        def _pause():
            return self.pause_processing()

        @self.app.route('/stopone', methods=['POST'])
        def _stop():
            action = request.json.get('action') if request.is_json else None
            return self.stop_cpp(action=action)

        @self.app.route('/stopbatch', methods=['POST'])
        def _stop_batch():
            return self.stop_cpp_batch()

        @self.app.route('/startone', methods=['POST'])
        def _startone():
            action = request.json.get('action') if request.is_json else None
            return self.start_cpp(action=action)

        @self.app.route('/demonstrateone', methods=['POST'])
        def _demonstrateone():
            data = request.get_json()
            if not data:
                return jsonify({"status": "error", "message": "请求数据为空，请提供 JSON 格式的请求数据"}), 400
            return self.demonstrate_cpp(action=data)

        @self.app.route('/startbatch', methods=['POST'])
        def _start_batch():
            action = request.json.get('action') if request.is_json else None
            return self.start_cpp_batch(action=action)

    def self_mount_usb(self):
        print("dsdsd")
        config = {
            "root_dir": "/data/mn4",
            "api_endpoint": "http://192.168.0.142:80/aiApi/aiSaveVideo",
            "timeout": 45,
            "max_retries": 3
        }
        try:
            result = get_latest_image("./results/video")
            self.lastest_img = result
            print(f"最新图片: {result or '未找到'}")
        except ValueError as e:
            print(e)
        uploader = VideoAPIUploader(**config)
        result = uploader.execute_upload()
        if result['status'] == 'success':
            print("上传成功！响应数据：", result['data'])
        else:
            print(f"错误发生：{result['error_type']}")
            print("错误信息：", result['message'])
            if 'status_code' in result:
                print("HTTP状态码：", result['status_code'])
        return jsonify({
            "status": "success",
            "results": result
        })

    def pause_processing(self):
        try:
            if self.cpp_pid == -1:
                return jsonify({
                    "status": "error",
                    "message": "没有正在运行的进程"
                }), 400
            current_os = platform.system()
            if self.cpp_pid != -1:
                os.kill(self.cpp_pid, signal.SIGKILL)
            return jsonify({
                "status": "success",
                "message": "处理已暂停",
                "pid": self.cpp_pid
            })
        except Exception as e:
            return self._error_response(str(e))

    def _error_response(self, message, status_code=500):
        return jsonify({
            "status": "error",
            "message": message
        }), status_code

    def run_program(self, send_info=False):
        try:
            print("enter run_program")
            needprocess = extract_videos_direct(self.video_queue)
            self.is_paused = False
            print("needprocess: ", needprocess)
            for task in needprocess:
                result = change_video_state(
                    camera_name=task["camera"],
                    video_name=task["video"].split('.')[0],
                    state=0
                )
                print(task)
                print("task[].split('.')[1] :", task["video"].split('.')[0])
                self.run_moive_task = get_parent_dir(task["video_path"])
                print(task["video_path"], "---------", get_parent_dir(task["video_path"]))
                if send_info:
                    gen_sdkconfig(task["video_path"], get_parent_dir(task["video_path"]))
                else:
                    gen_sdkconfig(task["video_path"], get_parent_dir(task["video_path"]))
                print("camera: ", task["camera"])
                print("video:", task["video"].replace('.', '_'))
                self.run_cpp_program(send_info=send_info)
                print("------185")
                if self.is_paused:
                    print("be kill")
                    break
                print("self.is_paused:----------- ", self.is_paused)
                if not self.is_paused:
                    uploader = EventUploader()
                    detect_event_dir = "/data/control_communication/" + task["camera"] + "/" + task["video"].replace('.', '_') + "/problem_cross"
                    uploader.generate_events(source_dir=detect_event_dir, output_dir=detect_event_dir)
                    report = uploader.upload_events(
                        event_dir=detect_event_dir,
                        api_url="http://192.168.0.142:80/aiApi/saveEvent",
                        camera_name=task["camera"],
                        video_name=task["video"].split('.')[0],
                        algorithm_id="2"
                    )
                    print(f"成功上传: {report['success']}/{report['total']}")
                    result = change_video_state(
                        camera_name=task["camera"],
                        video_name=task["video"].split('.')[0],
                        state=1
                    )
                    mark_video_processed(self.video_queue, extract_parent_directory(task["video_path"]), task["video_path"])
                output_file = "/data/newvideo_queue_info.json"
                try:
                    with open(output_file, 'w', encoding='utf-8') as f:
                        json.dump(self.video_queue, f, ensure_ascii=False, indent=4)
                except Exception as e:
                    print(f"写入 JSON 文件时出错: {e}")
                print("end ok2")
            self.cpp_pid = -1
        except json.JSONDecodeError as e:
            print("error")
            return self._error_response(f"队列文件格式错误: {str(e)}")
        except IOError as e:
            print("error1")
            return self._error_response(f"文件操作失败: {str(e)}")
        except Exception as e:
            print("error2")
            return self._error_response(str(e))

    def run_cpp_program(self, send_info=False):
        try:
            output_path = os.path.join(
                self.output_dir,
                f"output_{uuid.uuid4().hex}.ppm"
            )
            process = subprocess.Popen(
                ["/home/linaro/.vs/sdk-test/build/bin/sdk-test"],
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,
                text=True,
                encoding='utf-8',
                errors='replace'
            )
            output, error = "", ""
            self.cpp_pid = process.pid
            while True:
                if send_info:
                    print("send pic for demonstrate")
                    try:
                        
                        ws_thread = threading.Thread(target=lambda: asyncio.run(self.start_ws_server()))
                        ws_thread.daemon = True
                        ws_thread.start()
                        
                        # if self.lastest_img != result:
                        #     self.lastest_img = result
                            # self.lastest_img = result
                        
                            print(f"最新图片: {result or '未找到'}")
                            time.sleep(0.3)
                    except ValueError as e:
                        print(e)
                out_line = process.stdout.readline()
                if out_line:
                    output += out_line
                    print(f"[STDOUT] {out_line.strip()}")
                err_line = process.stderr.readline()
                if err_line:
                    error += err_line
                    print(f"[STDERR] {err_line.strip()}")
                if process.poll() is not None:
                    print("stop")
                    break
        except Exception as e:
            return self._error_response(f"{str(e)}\n[Error Output] {error}")

    def _async_execute(self, send_info=False):
        if self.processing_thread and self.processing_thread.is_alive():
            if self.cpp_pid != -1:
                try:
                    os.kill(self.cpp_pid, signal.SIGKILL)
                    self.cpp_pid = -1
                except ProcessLookupError:
                    pass
            self.is_paused = True
        time.sleep(1)
        self.processing_thread = threading.Thread(
            target=self._run_program_wrapper,
            kwargs={'send_info': send_info}
        )
        self.processing_thread.start()

    def _run_program_wrapper(self, send_info=True):
        try:
            self.run_program(send_info=send_info)
        except Exception as e:
            logging.error(f"异步执行异常: {str(e)}")

    def stop_cpp(self, action=None):
        print("only stop flag")
        print("here", (self.root_dir + "/" + action))
        print(self.video_queue)
        output_file = "/data/video_queue_info2.json"
        self.is_paused = True
        print("self.is_paused in stop_cpp : ", self.is_paused)
        if action == self.run_moive_task:
            print("action == self.run_moive_task")
            print("self.cpp_pid: ", self.cpp_pid)
            if self.cpp_pid != -1:
                print("kill self.cpp_pid: ", self.cpp_pid)
            modify_queue_info(self.video_queue, self.root_dir + "/" + action, queue_paused=True, custom_field=123)
            try:
                with open(output_file, 'w', encoding='utf-8') as f:
                    json.dump(self.video_queue, f, ensure_ascii=False, indent=4)
            except Exception as e:
                print(f"写入 JSON 文件时出错: {e}")
            self._async_execute()
        else:
            print("------------------1")
            modify_queue_info(self.video_queue, self.root_dir + "/" + action, queue_paused=True, custom_field=123)
            print("------------------2")
            try:
                with open(output_file, 'w', encoding='utf-8') as f:
                    json.dump(self.video_queue, f, ensure_ascii=False, indent=4)
            except Exception as e:
                print(f"写入 JSON 文件时出错: {e}")
            self._async_execute()
        results = []
        return jsonify({
            "status": "completed",
            "results": results
        })

    def stop_cpp_batch(self):
        output_file = "/data/video_queue_info3.json"
        try:
            data = request.get_json()
            self.is_paused = True
            if not data or 'camera_paths' not in data:
                return self._error_response("缺少camera_paths参数", 400)
            camera_paths = data['camera_paths']
            if not isinstance(camera_paths, list):
                return self._error_response("camera_paths必须是数组", 400)
            results = []
            for path in camera_paths:
                try:
                    if path == self.run_moive_task:
                        if self.cpp_pid != -1:
                            os.kill(self.cpp_pid, signal.SIGKILL)
                        self.cpp_pid = -1
                    modify_queue_info(self.video_queue, self.root_dir + "/" + path, queue_paused=True, custom_field=123)
                    results.append({
                        "camera_path": path,
                        "status": "success",
                        "stopped": (path == self.run_moive_task)
                    })
                except Exception as e:
                    results.append({
                        "camera_path": path,
                        "status": "error",
                        "message": str(e)
                    })
            with open(output_file, 'w', encoding='utf-8') as f:
                json.dump(self.video_queue, f, ensure_ascii=False, indent=4)
            self.is_paused = True
            self._async_execute()
            return jsonify({
                "status": "completed",
                "results": results
            })
        except Exception as e:
            return self._error_response(str(e))

    def demonstrate_start(self, action=None):
        output_file = "/data/video_queue_info4.json"
        print("hhhh")
        try:
            if not action:
                return self._error_response("缺少摄像头路径参数", 400)
            demonstrate = True
            if self.cpp_pid != -1:
                os.kill(self.cpp_pid, signal.SIGKILL)
            self.is_paused = True
            camera, video = action.split('/')
            video_path = find_videopath_by_camera_movie(camera, video, self.video_queue)
            gen_sdkconfig(task["video_path"], get_parent_dir(task["video_path"]))
            time.sleep(1)
            self.run_cpp_program()
            demonstrate = False
            self._async_execute()
            return jsonify({
                "status": "success",
                "message": f"摄像头任务已启动: {action}",
                "resumed": (action == self.run_moive_task)
            })
        except Exception as e:
            return self._error_response(str(e))

    def start_cpp(self, action=None):
        output_file = "/data/video_queue_info4.json"
        print("hhhh")
        try:
            if not action:
                return self._error_response("缺少摄像头路径参数", 400)
            self.is_paused = True
            print("self.is_paused in start_cpp : ", self.is_paused)
            modify_queue_info(self.video_queue, self.root_dir + "/" + action, queue_paused=False, custom_field=123)
            with open(output_file, 'w', encoding='utf-8') as f:
                json.dump(self.video_queue, f, ensure_ascii=False, indent=4)
            self._async_execute()
            return jsonify({
                "status": "success",
                "message": f"摄像头任务已启动: {action}",
                "resumed": (action == self.run_moive_task)
            })
        except Exception as e:
            return self._error_response(str(e))

    def demonstrate_cpp(self, action=None):
        output_file = "/data/video_queue_info5.json"
        print("hhhh")
        camera_name = action.get('cameraName')
        video_name = action.get('videoName')
        try:
            if not action:
                return self._error_response("缺少摄像头视频参数", 400)
            self.is_paused = True
            print("demonstrate_cpp output_file: ", output_file)
            print("self.root_dir camera_name: ", self.root_dir + "/" + camera_name)
            adjust_priority_and_pause(self.video_queue, self.root_dir + "/" + camera_name, video_name, custom_field=123)
            with open(output_file, 'w', encoding='utf-8') as f:
                json.dump(self.video_queue, f, ensure_ascii=False, indent=4)
            self._async_execute()
            return jsonify({
                "status": "success",
                "message": f"摄像头任务已启动: {camera_name}",
                "resumed": (camera_name == self.run_moive_task)
            })
        except Exception as e:
            return self._error_response(str(e))

    def start_cpp_batch(self, action=None):
        output_file = "/data/video_queue_info4.json"
        try:
            data = request.get_json()
            if not data or 'camera_paths' not in data:
                return self._error_response("缺少camera_paths参数", 400)
            camera_paths = data['camera_paths']
            if not isinstance(camera_paths, list):
                return self._error_response("camera_paths必须是数组", 400)
            results = []
            for path in camera_paths:
                try:
                    modify_queue_info(self.video_queue, self.root_dir + "/" + path, queue_paused=False, custom_field=123)
                    results.append({
                        "camera_path": path,
                        "status": "success"
                    })
                except Exception as e:
                    results.append({
                        "camera_path": path,
                        "status": "error",
                        "message": str(e)
                    })
            with open(output_file, 'w', encoding='utf-8') as f:
                json.dump(self.video_queue, f, ensure_ascii=False, indent=4)
            self.is_paused = True
            self._async_execute()
            return jsonify({
                "status": "completed",
                "results": results
            })
        except Exception as e:
            return self._error_response(str(e))

    def run(self, debug=False):
        self.app.run(host=self.host, port=self.port, debug=debug)

    async def push_single_image(self, websocket):
        """推送指定图片给客户端"""
        try:
            # lastest_img
            result = get_latest_image("./results/video")
            if result != self.lastest_img
                with open(self.lastest_img, "rb") as f:
                    image_data = f.read()
                while True:
                    await websocket.send(image_data)
                    print(f"成功发送图片: {os.path.basename(self.lastest_img)}")
                    await asyncio.sleep(self.SEND_INTERVAL)
        except FileNotFoundError:
            print(f"图片文件已被移除: {self.lastest_img}")
        except Exception as e:
            print(f"发送失败: {str(e)}")

    async def handle_connection(self, websocket, path):
        """处理客户端连接"""
        client_ip = websocket.remote_address[0]
        print(f"客户端连接: {client_ip}")
        try:
            await self.push_single_image(websocket)
        except websockets.exceptions.ConnectionClosed:
            print(f"客户端断开: {client_ip}")
        finally:
            await websocket.close()

    async def start_ws_server(self):
        async with websockets.serve(self.handle_connection, "0.0.0.0", self.WS_PORT):
            print(f"图片推送服务已启动，监听端口: {self.WS_PORT}")
            print(f"正在推送指定图片: {self.lastest_img}")
            await asyncio.Future()
    